package com.csw.shuanfa.utils;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class ThreadPoolUtil {

    /**
     * 【线程池】
     * 使用线程池的10个坑_threadpool nullpointer-CSDN博客  https://blog.csdn.net/weiwenhou/article/details/126358283
     *
     * //建议在方法里面调用getExecutorServiceCPU方法
     *  ExecutorService threadPool = ThreadPoolUtil.getExecutorServiceCPU();
     *   List<CompletableFuture> completableFutureList = new ArrayList<>();
     *
     *         try {
     *             CompletableFuture<Void> step1 = CompletableFuture.runAsync(() -> {
     *             }, threadPool);
     * completableFutureList.add(future1);
     *
     *             //批量阻塞完成
     *             // CompletableFuture.allOf(futureList.toArray(futureList.toArray(new CompletableFuture[0]))).get(1, TimeUnit.SECONDS);
     *             //CompletableFuture.allOf(future1, future2, future3, future4, future5, future6, future7).get(1, TimeUnit.SECONDS);
     *
     *         } catch (Exception e) {
     *             System.out.println(ThreadPoolUtil.getThreadPoolName());
     *             threadPool.shutdownNow();
     *             throw new RuntimeException(e);
     *         } finally {
     *             threadPool.shutdown();
     *         }
     */


    /**
     * 在方法里面调用推荐
     * AbortPolicy-拒绝并抛出异常
     */
    public static ExecutorService getExecutorServiceCPU() {
        return getExecutorServiceCPU(false, 0, new ThreadPoolExecutor.AbortPolicy());
    }


    /**
     * @param type true是偏向IO处理连接
     */
    public static ExecutorService getExecutorServiceCPU(boolean type) {
        return getExecutorServiceCPU(type, 0, new ThreadPoolExecutor.AbortPolicy());
    }


    /**
     * @param queneSize 队列大小
     */
    public static ExecutorService getExecutorServiceCPU(int queneSize) {
        return getExecutorServiceCPU(false, queneSize, new ThreadPoolExecutor.AbortPolicy());
    }

    /**
     * @param queneSize 队列大小
     *                  <p>
     *                  拒绝策略
     *                  AbortPolicy-拒绝并抛出异常
     *                  CallerRunsPolicy-回调等待不抛出异常
     *                  DiscardPolicy-丢弃新任务不抛弃异常
     *                  DiscardOldestPolicy-丢弃老任务不抛弃异常
     *                  <p>
     *                  有队列长度才指定决绝策略
     */
    public static ExecutorService getExecutorServiceCPU(int queneSize, RejectedExecutionHandler handler) {
        return getExecutorServiceCPU(false, queneSize, handler);
    }


    /**
     * @param type      true是偏向IO处理连接
     * @param queneSize 队列大小
     */
    public static ExecutorService getExecutorServiceCPU(boolean type, int queneSize) {
        return getExecutorServiceCPU(type, queneSize, new ThreadPoolExecutor.AbortPolicy());
    }


    /**
     * @param type      true是偏向IO处理连接
     * @param queneSize 队列大小
     *                  <p>
     *                  拒绝策略
     *                  AbortPolicy-拒绝并抛出异常
     *                  CallerRunsPolicy-回调等待不抛出异常
     *                  DiscardPolicy-丢弃新任务不抛弃异常
     *                  DiscardOldestPolicy-丢弃老任务不抛弃异常
     *                  <p>
     *                  有队列长度才指定决绝策略
     *
     *                  在一个数据处理应用中，线程池的核心线程数为 5，最大线程数为 10，任务队列大小为 20。当已经有 5 个任务在核心线程中执行，20 个任务在任务队列中等待，并且又有新任务提交时，就会创建新的非核心线程（最多到 10 个线程）来处理这些新任务。
     *                  当队列满了才会用最大线程数
     */
    public static ExecutorService getExecutorServiceCPU(boolean type, int queneSize, RejectedExecutionHandler handler) {
        int cpuCounts = Runtime.getRuntime().availableProcessors();
        if (cpuCounts <= 8) {
            cpuCounts = 8;
        }
        if (queneSize == 0) {
            queneSize = Integer.MAX_VALUE;
        }
        int poolsize = 0;
        if (type == true) {//偏向IO处理连接
            poolsize = cpuCounts * 2 - 1;
        } else {//cpu型任务任务运行时间快，像单线程处理
            poolsize = cpuCounts - 1;
        }

        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat(getThreadPoolNameMethod() + "-%d").build();
        ExecutorService threadPool = new ThreadPoolExecutor(poolsize, poolsize * 2, 60L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(queneSize), namedThreadFactory, handler);
        return threadPool;
    }

    /**
     * 获取线程池名称
     *
     * @return
     */
    public static String getThreadPoolNameMethod() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        int j = 0;
        //设置没有出现过
        boolean flag = false;
        for (int i = 0; i < stackTrace.length; i++) {
            StackTraceElement element = stackTrace[i];
            //stackTrace[1]是当前方法
            if (element.getFileName().equals(stackTrace[1].getFileName())) {
                flag = true;
            } else {
                if (flag == true) {//一旦不相等，并且之前出现过flag=true，就是调用出
                    j = i;
                    break;
                }
            }
        }
        StackTraceElement element = Thread.currentThread().getStackTrace()[j];
        String threadPoolName = element.getMethodName() + "_" + element.getFileName();
        return threadPoolName;
    }
}
